---
title: Convert (file-shaped)
summary: Converts raw uploaded bytes to PDF using a route-supplied file extension, otherwise identical to the request-shaped convert operation.
status: draft
owner: Not determined from source
last_reviewed: 2026-09-17
library: PdfAPI
reference_type: embedded
operation_id: OP-CONVERT-FILE
trigger: Client submits a POST v1/convert/{fileExtension} request with raw document bytes
---

# OP-CONVERT-FILE: Convert (file-shaped)

Converts raw document bytes submitted directly in the request body to PDF or PDF/A, using the route-supplied `fileExtension` in place of a `ConvertRequest.FileExtension` field. All other processing is identical to [OP-CONVERT-REQUEST](op-convert-request.md).

| Field | Value |
| --- | --- |
| **Operation ID** | OP-CONVERT-FILE |
| **Trigger** | Client submits `POST v1/convert/{fileExtension}` with raw bytes in the body |
| **Entry endpoint** | [`POST v1/convert/{fileExtension}`](../endpoints/convert-controller.md#post-v1%2Fconvert%2F%7Bfileextension%7D) |
| **Owning component** | `ConvertController.Convert(byte[] file, string fileExtension, PdfFormat format)` → `IPdfService.Convert(request)` |
| **Inputs** | `fileExtension` route segment, raw `byte[]` body |
| **Outputs** | `PdfResult` (`Status`, `Message`, `Document`, `TrackingId`); a `PDFTracking` row created/updated; optionally an incident email |
| **Failure response** | Caught exceptions are logged and returned as `Ok(new PdfResult(message))` — HTTP `200` |

## Steps

1. The action constructs a `ConvertRequest` internally from `fileExtension` and the raw bytes, then wraps the call in `try`/`catch` ([BR-PDFAPI-017](../business-rules.md#br-pdfapi-017-processing-failures-return-200-with-a-pdfresult)).
   - On any exception: `_logService.LogException("pdfapi", "Convert", "<detail>", ex)`, then `Ok(new PdfResult(ex.Message, request: request))` — HTTP `200`, produced by the action's own `catch` block.
2. `PdfServiceFactory.Create()` reads `pdfapi.pdfservicetype` and selects the processor ([BR-PDFAPI-003](../business-rules.md#br-pdfapi-003-processor-selection-by-configuration)) — identical selection logic to OP-CONVERT-REQUEST.
3. Tracking record creation, temp-storage save, processor dispatch, `FinalizeResult`, and
   incident-email notification follow the same shared path as [OP-CONVERT-REQUEST](op-convert-request.md) steps 3–8:
   1. If tracking is enabled (default, or forced on by `SendHeatEmailOnFailure`, [BR-PDFAPI-010](../business-rules.md#br-pdfapi-010-tracking-forced-on-with-heat-email)), `PdfTrackingService.CreateTrackingRecord` inserts a `PDFTracking` row with status `SCHED` ([data model](../data-model.md#pdftracking-properties-observed-in-use)), then updates it to `PROC`.
   2. When `pdfapi.saveInputToTemp` is enabled, the inbound bytes are written to temporary storage before conversion ([BR-PDFAPI-016](../business-rules.md#br-pdfapi-016-save-input-to-temp-storage)).
   3. On the Syncfusion path (default), `ConverterFactory.Convert(request)` dispatches on the lower-cased, trimmed file extension: an unrecognized extension returns a failure `PdfResult` whose `Status` is left at the enum default `NotTracked` ([BR-PDFAPI-008](../business-rules.md#br-pdfapi-008-unsupported-extension-leaves-status-at-default)), and plain-text (`.txt`) input is converted twice — to an intermediate document, then to PDF ([BR-PDFAPI-009](../business-rules.md#br-pdfapi-009-plain-text-double-conversion)).
   4. On the ActivePDF path (`pdfapi.pdfservicetype == "activepdf"`): if `SkipPdf` is set (default `true`) and the input is already a PDF, conversion is short-circuited and the input is returned as the output ([BR-PDFAPI-019](../business-rules.md#br-pdfapi-019-skip-conversion-when-input-is-already-pdf)). A PDF/A production failure is retried as plain PDF, and configured `pdfApi.ErrorsToRetry` error codes trigger a whole-operation retry ([BR-PDFAPI-020](../business-rules.md#br-pdfapi-020-activepdf-retry-behavior)).
   5. `FinalizeResult` stamps `TrackingId`, `PdfProcessorType`, `FilePath` on the result, then persists the terminal tracking status (`SUCC`/`ERROR`) via `PdfTrackingService.UpdateTrackingRecord`.
   6. If the result failed and `SendHeatEmailOnFailure` is set, `PdfService.SendIncidentEmail` sends a notification using `noreplyemailsenderaddress`/`pdfapi.ErrorEmail.Recipient` and the tracking record's `ApplicationError.HeatEmailSubject` ([BR-PDFAPI-015](../business-rules.md#br-pdfapi-015-incident-email-on-failure)).

   > **Origin:** Steps 3.1–3.6 are the shared conversion path implemented for both convert
   > endpoints. They are documented in full at
   > [OP-CONVERT-REQUEST](op-convert-request.md) steps 3–8; this page embeds them here so the
   > file-shaped operation's behavior is complete without cross-page lookup.
4. The controller returns `Ok(result)` — HTTP `200` regardless of whether the conversion succeeded or failed.

## Process flow

The following diagram shows the route-binding, processor-selection, tracking, and incident-email sequence for a file-upload conversion request.

```mermaid
flowchart TD
    A["POST v1/convert/fileExtension"] --> B["Build ConvertRequest from route and body"]
    B --> C["PdfServiceFactory.Create selects processor"]
    C --> D["Create tracking record<br>SCHED to PROC"]
    D --> E{"Processor"}
    E -->|Syncfusion default| F["ConverterFactory.Convert"]
    E -->|ActivePDF| G["ActivePdfService.Convert"]
    F --> H["FinalizeResult: persist terminal status"]
    G --> H
    H --> I{"Result failed and<br>SendHeatEmailOnFailure?"}
    I -->|Yes| J["Send incident email"]
    I -->|No| K["Ok result"]
    J --> K
```

## Transaction and side effects

| Aspect | Finding |
| --- | --- |
| Unit of work | `IUnitOfWorkFactory("oracle")`, `InstancePerRequest` |
| Commit point | `PdfTrackingService.CreateTrackingRecord` and `UpdateTrackingRecord`, each bracketed by `_uow.Begin()`/`_uow.Commit()` |
| Records written | `PDFTracking` ([data model](../data-model.md#pdftracking-properties-observed-in-use)) |
| Downstream calls | Outbound SMTP email on failure when `SendHeatEmailOnFailure` is set |
| Repeat-call behavior | Each call creates a new tracking record; not idempotent |

## Logging

| Surface | Written content |
| --- | --- |
| `ILogService.LogException` | `"pdfapi"`, `"Convert"`, and exception detail, on any caught failure |
| `ILogService.TraceError` / `TraceWarn` / `TraceDebug` | Emitted from `ActivePdfService` on the ActivePDF processor path |

## Error handling

- Any exception during processing: caught in the action, logged, returned as `Ok(new PdfResult(message))` — HTTP `200` ([BR-PDFAPI-017](../business-rules.md#br-pdfapi-017-processing-failures-return-200-with-a-pdfresult)).
- Unrecognized file extension: a failure `PdfResult` with `Status == NotTracked` ([BR-PDFAPI-008](../business-rules.md#br-pdfapi-008-unsupported-extension-leaves-status-at-default)).

## Related documentation
- [API index](../index.md)
- [Overview](../overview.md)
- [Architecture](../architecture.md)
- [Endpoints](../endpoints.md)
- [Authentication and authorization](../authentication-authorization.md)
- [Dependencies](../dependencies.md)
- [Configuration](../configuration.md)
- [Operations and processes](../operations-processes.md)
- [Business rules](../business-rules.md)
- [Data model](../data-model.md)
- [Operational runbook](../operational-runbook.md)
- [Tech debt](../tech-debt.md)

## Sources
- PdfAPI\Controllers\v1\ConvertController.cs
- PdfAPI\Services\PdfServiceFactory.cs
- PdfAPI\Services\PdfService.cs
- PdfAPI\Services\PdfTrackingService.cs
- PdfAPI\Services\ActivePdf\ActivePdfService.cs
- PdfApi.SyncFusionCore\Convert\ConverterFactory.cs
